package com.corejsf;

import java.io.Serializable;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import javax.annotation.Resource;
import javax.enterprise.context.SessionScoped;
import javax.inject.Inject;
import javax.inject.Named;
import javax.sql.DataSource;

/**
 *
 * Scheduler class is used by users to manage their timesheets.
 *
 * @author Victor Lu
 * @version 1.0
 *
 */
@SessionScoped
@Named ("scheduler")
public class Scheduler implements Serializable {
    /**
     *  serialVersionUID.
     */
    private static final long serialVersionUID = 2269996014365436200L;
    /**
     * timeSheet - Arraylist of Timesheet beans (which are the displayed rows).
     */
    private static ArrayList<Timesheet> timeSheets = new ArrayList<Timesheet>();

    /**
     * Number of timesheet slots to display initially.
     */
    private static final int INITIALTIMESLOTS = 5;

    /**
     * Max number of timesheet slots to display.
     */
    private static final int MAXTIMESLOTS = 10;

    /**
     * Week number being viewed in the OldTimeSheets view.
     */
    private int pastWeekNum = 1;
    /**
     * LinkedHashMap holds the values of the dropdown list of weeks.
     */
    private LinkedHashMap<String, Integer> weekCount;

    /**
     * DataSource for JBoss AS 7.1 connection pool.
     */
    @Resource(mappedName = "java:jboss/datasources/vvdb")
    private DataSource dataSource;

    /**
     * Set by User when it instantiates its scheduler.
     */
    @Inject private Credentials cred;

    /**
     * Constructor.
     */
    public Scheduler() {
    }

    /**
     * Increment current week.
     */
    public void nextWeek() {
        save();
        timeSheets.clear();
        timeSheets = getTimeSheets();
        Connection connection = null;
        PreparedStatement stmt = null;
        try {
            try {
                connection = dataSource.getConnection();
                try {
                    stmt = connection.prepareStatement("UPDATE Users SET "
                        + "CurrentWeek = CurrentWeek + 1 WHERE UserName = ?");
                    stmt.setString(1, cred.getUsername());
                    stmt.executeUpdate();
                } finally {
                    if (stmt != null) {
                        stmt.close();
                    }
                }
            } finally {
                if (connection != null) {
                    connection.close();
                }
            }
        } catch (SQLException ex) {
            System.out.println("Error in nextWeek()");
            ex.printStackTrace();
        }
    }

    /**
     * Get week number.
     *
     * @return returnValue
     */
    public int getWeekNum() {
        Connection connection = null;
        PreparedStatement stmt = null;
        int returnValue = -1;
        try {
            try {
                connection = dataSource.getConnection();
                try {
                    stmt = connection.prepareStatement("SELECT "
                        + "MAX(currentWeek) FROM users "
                        + "WHERE EmployeeNumber = ?");
                    stmt.setInt(1, cred.getEmployeeNumber());
                    ResultSet result = stmt.executeQuery();
                    result.next();
                    returnValue = result.getInt("MAX(currentWeek)");
                    if (returnValue < 1) {
                        returnValue = 1;
                    }
                } finally {
                    if (stmt != null) {
                        stmt.close();
                    }

                }
            } finally {
                if (connection != null) {
                    connection.close();
                }
            }
        } catch (SQLException ex) {
            System.out.println("Error in getWeekNum()");
            ex.printStackTrace();
        }
        return returnValue;
    }

    /**
     * Returns whether timesheets contain data or not.
     *
     * @return "isEmpty" or "hasData"
     */
    public String timeSheetHasValue() {
        if (timeSheets.size() > 0) {
            for (int i = 0; i > timeSheets.size(); i++) {
                if (timeSheets.get(i).getProject() > 0) {
                    return "hasData";
                }
            }
        }
        return "isEmpty";
    }

    /**
     * Gets timesheets.
     *
     * @return timeSheets
     */
    public ArrayList<Timesheet> getTimeSheets() {
        String sheetStatus = timeSheetHasValue();
        if (sheetStatus == "hasData") {
            Connection connection = null;
            PreparedStatement stmt = null;
            try {
                try {
                    Timesheet temp;
                    connection = dataSource.getConnection();
                    try {
                        int empNo = cred.getEmployeeNumber();
                        int weekNo = getWeekNum();
                        stmt = connection.prepareStatement("SELECT * FROM "
                                + "Timesheets WHERE EmployeeNumber = ? AND "
                                + "WeekNumber = ?");
                        stmt.setInt(1, empNo);
                        stmt.setInt(2, weekNo);
                        ResultSet result = stmt.executeQuery();
                        while (result.next()) {
                            temp = new Timesheet();
                            temp.setProject(result.getDouble("project"));
                            temp.setWp(result.getString("wp"));
                            temp.setTotal(result.getDouble("total"));
                            temp.setSat(result.getDouble("sat"));
                            temp.setSun(result.getDouble("sun"));
                            temp.setMon(result.getDouble("mon"));
                            temp.setTue(result.getDouble("tue"));
                            temp.setWed(result.getDouble("wed"));
                            temp.setThu(result.getDouble("thu"));
                            temp.setFri(result.getDouble("fri"));
                            temp.setNotes(result.getString("notes"));
                            timeSheets.add(temp);
                        }
                    } finally {
                        if (stmt != null) {
                            stmt.close();
                        }

                    }
                } finally {
                    if (connection != null) {
                        connection.close();
                    }
                }
            } catch (SQLException ex) {
                System.out.println("Error in getTimeSheets");
                ex.printStackTrace();
            }
        }
        if (sheetStatus == "isEmpty") {
            if (timeSheets.isEmpty()) {
                timeSheets = new ArrayList<Timesheet>();
                for (int i = 0; i < INITIALTIMESLOTS; i++) {
                    timeSheets.add(new Timesheet());
                }
            }
        }

        return timeSheets;
    }

    /**
     * Adds a row to the current timeSheet.
     */
    public void addRow() {
        if (timeSheets.size() < MAXTIMESLOTS) {
            timeSheets.add(new Timesheet());
        }
    }

    /**
     * Deletes a row from the current timeSheet.
     */
    public void deleteRow() {
        if (timeSheets.size() != 0) {
            timeSheets.remove(timeSheets.size() - 1);
        }
        save();
    }

    /**
     * Updates timesheets in database.
     */
    public void save() {
        Connection connection = null;
        PreparedStatement stmt = null;
        try {
            try {
                connection = dataSource.getConnection();
                try {
                    stmt = connection.prepareStatement(
                              "DELETE FROM Timesheets "
                            + "WHERE EmployeeNumber = ? "
                            + "AND WeekNumber = ?");
                    stmt.setDouble(1, cred.getEmployeeNumber());
                    stmt.setDouble(2, getWeekNum());
                    stmt.executeUpdate();
                } finally {
                    if (stmt != null) {
                        stmt.close();
                    }

                }
            } finally {
                if (connection != null) {
                    connection.close();
                }
            }
        } catch (SQLException ex) {
            System.out.println("Error in save(updatedTimesheets)");
            ex.printStackTrace();
        }

        for (int i = 0; i < timeSheets.size(); i++) {
            if (timeSheets.get(i).getProject() != 0
                && timeSheets.get(i).getWp() != null) {
                try {
                    try {
                        connection = dataSource.getConnection();
                        try {
                            stmt = connection.prepareStatement(
                                      "INSERT INTO Timesheets"
                                    + "(EmployeeNumber, WeekNumber, Project"
                                    + ", WP, Total, Sat, Sun, Mon, Tue, Wed,"
                                    + "Thu, Fri, Notes)"
                                    + "VALUES( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?"
                                    + ", ?, ?, ?)");
                            stmt.setDouble(1, cred.getEmployeeNumber());
                            stmt.setDouble(2, getWeekNum());
                            stmt.setDouble(3, timeSheets.get(i).getProject());
                            stmt.setString(4, timeSheets.get(i).getWp());
                            stmt.setDouble(5, timeSheets.get(i).getTotal());
                            stmt.setDouble(6, timeSheets.get(i).getSat());
                            stmt.setDouble(7, timeSheets.get(i).getSun());
                            stmt.setDouble(8, timeSheets.get(i).getMon());
                            stmt.setDouble(9, timeSheets.get(i).getTue());
                            stmt.setDouble(10, timeSheets.get(i).getWed());
                            stmt.setDouble(11, timeSheets.get(i).getThu());
                            stmt.setDouble(12, timeSheets.get(i).getFri());
                            stmt.setString(13, timeSheets.get(i).getNotes());
                            stmt.executeUpdate();
                        } finally {
                            if (stmt != null) {
                                stmt.close();
                            }

                        }
                    } finally {
                        if (connection != null) {
                            connection.close();
                        }
                    }
                } catch (SQLException ex) {
                    System.out.println("Error in save(updatedTimesheets)");
                    ex.printStackTrace();
                }
            }
        }
        timeSheets = getTimeSheets();
    }

    /**
     * Sums up the 'Total' columnn.
     *
     * @return the total of the column.
     */
    public double getColumnTotal() {
        double columnTotal = 0;

        for (int i = 0; i < timeSheets.size(); i++) {
            columnTotal += timeSheets.get(i).getTotal();
        }
        return columnTotal;
    }

    /**
     * Sums up the 'Sat' column.
     *
     * @return the total of the column.
     */
    public double getSatTotal() {
        double satTotal = 0;
        for (int i = 0; i < timeSheets.size(); i++) {
            satTotal += timeSheets.get(i).getSat();
        }
        return satTotal;
    }

    /**
     * Sums up the 'Sun' column.
     *
     * @return the total of the column.
     */
    public double getSunTotal() {
        double sunTotal = 0;
        for (int i = 0; i < timeSheets.size(); i++) {
            sunTotal += timeSheets.get(i).getSun();
        }
        return sunTotal;
    }

    /**
     * Sums up the 'Mon' column.
     *
     * @return the total of the column.
     */
    public double getMonTotal() {
        double monTotal = 0;
        for (int i = 0; i < timeSheets.size(); i++) {
            monTotal += timeSheets.get(i).getMon();
        }
        return monTotal;
    }

    /**
     * Sums the 'Tue' column.
     *
     * @return the total of the column.
     */
    public double getTueTotal() {
        double tueTotal = 0;
        for (int i = 0; i < timeSheets.size(); i++) {
            tueTotal += timeSheets.get(i).getTue();
        }
        return tueTotal;
    }

    /**
     * Sums up the 'Wed' column.
     *
     * @return the total of the column.
     */
    public double getWedTotal() {
        double wedTotal = 0;
        for (int i = 0; i < timeSheets.size(); i++) {
            wedTotal += timeSheets.get(i).getWed();
        }
        return wedTotal;
    }

    /**
     * Sums up the 'Thu' column.
     *
     * @return the total of the column.
     */
    public double getThuTotal() {
        double thuTotal = 0;
        for (int i = 0; i < timeSheets.size(); i++) {
            thuTotal += timeSheets.get(i).getThu();
        }
        return thuTotal;
    }

    /**
     * Sums up the 'Fri' column.
     *
     *@return the total of the column.
     */
    public double getFriTotal() {
        double friTotal = 0;
        for (int i = 0; i < timeSheets.size(); i++) {
            friTotal += timeSheets.get(i).getFri();
        }
        return friTotal;
    }

    /**
     * Adds the current week into the dropdown list represented
     * by a linked hash map.
     *
     * @return week count.
     */
    public LinkedHashMap<String, Integer> getWeekCount() {
        int weeks = getWeekNum() - 1;
        weekCount = new LinkedHashMap<String, Integer>();
        for (int i = 1; i <= weeks; i++) {
            this.weekCount.put("Week " + i, i);
        }
        return weekCount;
    }

    /**
     * Gets the past week number.
     *
     * @return pastWeekNum
     */
    public int getPastWeekNum() {
        return pastWeekNum;
    }

    /**
     * Sets the past week number.
     * @param pastWeekNum old week number
     */
    public void setPastWeekNum(int pastWeekNum) {
        this.pastWeekNum = pastWeekNum;
    }

    /**
     * Get the values of the old week.
     *
     * This function only called if oldTimeSheets.size() != 0
     * see oldTimeSheets.xhtml
     *
     * @return the stored TimeSheets
     */
    public ArrayList<Timesheet> getPastWeek() {
        Connection connection = null;
        PreparedStatement stmt = null;
        ArrayList<Timesheet> pastWeek = new ArrayList<Timesheet>();
        try {
            try {
                connection = dataSource.getConnection();
                try {
                    Timesheet temp;
                    stmt = connection.prepareStatement(
                            "SELECT * FROM Timesheets "
                            + "WHERE EmployeeNumber = ? "
                            + "AND WeekNumber = ?");
                    stmt.setDouble(1, cred.getEmployeeNumber());
                    stmt.setDouble(2, pastWeekNum);
                    ResultSet result = stmt.executeQuery();
                    while (result.next()) {
                        temp = new Timesheet();
                        temp.setProject(result.getDouble("project"));
                        temp.setWp(result.getString("wp"));
                        temp.setTotal(result.getDouble("total"));
                        temp.setSat(result.getDouble("sat"));
                        temp.setSun(result.getDouble("sun"));
                        temp.setMon(result.getDouble("mon"));
                        temp.setTue(result.getDouble("tue"));
                        temp.setWed(result.getDouble("wed"));
                        temp.setThu(result.getDouble("thu"));
                        temp.setFri(result.getDouble("fri"));
                        temp.setNotes(result.getString("notes"));
                        pastWeek.add(temp);
                    }
                } finally {
                    if (stmt != null) {
                        stmt.close();
                    }

                }
            } finally {
                if (connection != null) {
                    connection.close();
                }
            }
        } catch (SQLException ex) {
            System.out.println("Error in getPastWeek()");
            ex.printStackTrace();
        }
        return pastWeek;

    }

    /**
     * Get credentials.
     *
     * @return cred
     */
    public Credentials getCred() {
        return cred;
    }

    /**
     * Sets credentials.
     *
     * @param cred
     */
    public void setCred(Credentials cred) {
        this.cred = cred;
    }
}
